<template>
	<view ref="xlRate" class="xl-rate" :style="{ 'justify-content' : (align=='right' ? 'flex-end' : (align=='center' ? 'center':'flex-start'))}">
		<view
			class="xl-rate__icon"
			:class="{'xl-cursor-not-allowed': disabled, 'first-start': index == 0}"
			:style="{ 'margin-right': margin + 'px'}"
			v-for="(star, index) in stars"
			:key="index"
			@touchstart.stop="touchstart"
			@touchmove.stop="touchmove"
			@mousedown.stop="mousedown"
			@mousemove.stop="mousemove"
			@mouseleave="mouseleave"
		>
			<xl-icon :color="color" :size="size" :name="fill ? 'xl-star-filled' : 'xl-star'"/>
			<!-- #ifdef APP-NVUE -->
			<view :style="{ width: star.activeWitch.replace('%','')*size/100+'px'}" class="xl-rate__icon-on">
				<xl-icon style="text-align: left;" :color="disabled?'#ccc':activeColor" :size="size" name="xl-star-filled"/>
			</view>
			<!-- #endif -->
			<!-- #ifndef APP-NVUE -->
			<view :style="{ width: star.activeWitch}" class="xl-rate__icon-on">
				<xl-icon :color="disabled ? disabledColor : activeColor" :size="size" name="xl-star-filled"/>
			</view>
			<!-- #endif -->
		</view>
	</view>
</template>

<script setup>
	import {ref, watch, computed, onMounted, getCurrentInstance} from 'vue'
	import propsData from './props.js'
	const props = defineProps(propsData)
	
	const emits = defineEmits(['update:modelValue', 'change'])
	
	const valueSync = ref('')
	const userMouseFristMove = ref(true)
	const userRated = ref(false)
	const userLastRate = ref(1)
	let _oldValue = ''
	let PC = false
	
	watch(() => props.modelValue, newVal => {
		valueSync.value = Number(newVal);
	})
	
	const stars = computed(() =>{
		const value = valueSync.value ? valueSync.value  : 0;
		const starList = [];
		const floorValue = Math.floor(value);
		const ceilValue = Math.ceil(value);
		for (let i = 0; i < props.max; i++) {
			if (floorValue > i) {
				starList.push({
					activeWitch: "100%"
				});
			} else if (ceilValue - 1 === i) {
				starList.push({
					activeWitch: (value - floorValue) * 100 + "%"
				});
			} else {
				starList.push({
					activeWitch: "0"
				});
			}
		}
		return starList;
	})
	
	onMounted(() =>{
		valueSync.value = Number(props.modelValue);
		_oldValue = null
		// #ifdef H5
		PC = IsPC()
		// #endif
	})
	
	function touchstart(e) {
		// #ifdef H5
		if( IsPC() ) return
		// #endif
		if (props.readonly || props.disabled) return
		const {
			clientX,
			screenX
		} = e.changedTouches[0]
		// TODO 做一下兼容，只有 Nvue 下才有 screenX，其他平台式 clientX
		_getRateCount(clientX || screenX)
	}
	
	function touchmove(e) {
		// #ifdef H5
		if( IsPC() ) return
		// #endif
		if (props.readonly || props.disabled || !props.touchable) return
		const {
			clientX,
			screenX
		} = e.changedTouches[0]
		_getRateCount(clientX || screenX)
	}
	
	/**
	 * 兼容 PC @tian
	 */
	
	function mousedown(e) {
		// #ifdef H5
		if( !IsPC() ) return
		if (props.readonly || props.disabled) return
		const {
			clientX,
		} = e
		userLastRate.value = valueSync.value
		_getRateCount(clientX)
		userRated.value = true
		// #endif
	}
	
	function mousemove(e) {
		// #ifdef H5
		if( IsPC() ) return
		if( userRated.value ) return
		if( userMouseFristMove.value ) {
			userLastRate.value = valueSync.value
			userMouseFristMove.value = false
		}
		if (props.readonly || props.disabled || !props.touchable) return
		const {
			clientX,
		} = e
		_getRateCount(clientX)
		// #endif
	}
	
	function mouseleave(e) {
		// #ifdef H5
		if( !IsPC() ) return
		if (props.readonly || props.disabled || !props.touchable) return
		if( userRated.value ) {
			userRated.value = false
			return
		}
		valueSync.value = userLastRate.value
		// #endif
	}
	
	
	// #ifdef H5
	function IsPC() {
		var userAgentInfo = navigator.userAgent;
		var Agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"];
		var flag = true;
		for (let v = 0; v < Agents.length - 1; v++) {
			if (userAgentInfo.indexOf(Agents[v]) > 0) {
				flag = false;
				break;
			}
		}
		return flag;
	}
	// #endif
	
	/**
	 * 获取星星个数
	 */
	async function _getRateCount(clientX) {
		const size = Number(props.size)
		if(size === NaN){
			return new Error('size 属性只能设置为数字')
		}
		let box = await getElementInfo('.first-start');
		const rateMoveRange = clientX - box.left;
		let index = parseInt(rateMoveRange / (size + props.margin))
		index = index < 0 ? 0 : index;
		index = index > props.max ? props.max : index;
		const range = parseInt(rateMoveRange - (size + props.margin) * index);
		let value = 0;
		
		if (_oldValue === index && !PC) return;
		_oldValue = index;
		if (props.allowHalf) {
			if (range > (size / 2)) {
				value = index + 1
			} else {
				value = index + 0.5
			}
		} else {
			value = index + 1
		}
	
		value = Math.max(0.5, Math.min(value, props.max))
		valueSync.value = value
		_onChange()
	}
	
	
	const instance = getCurrentInstance()
	// #ifdef APP-NVUE
	const xlRate = ref()
	const dom = uni.requireNativePlugin('dom');
	// #endif
	//得到元素的size  用来获取星星距离屏幕左侧距离
	function getElementInfo(ele) { 
	    return new Promise((res, rej) => {
			// #ifndef APP-NVUE
			// 注意小程序中需要加上.in(this)才能获取
			// 选择器仅选取页面范围的节点，不会选取任何自定义组件中的节点，选择器的选取范围更改为自定义组件 component 内
			uni.createSelectorQuery().in(instance.proxy).select(ele).fields({
				rect: true
			}, (data) => {
				res(data);
			}).exec();
			// #endif
			// #ifdef APP-NVUE
			dom.getComponentRect(xlRate.value, (ret) => {
				const size = ret.size
				if (size) {
					res(size);
				}
			})
			// #endif
	    })
	}
	
	/**
	 * 触发动态修改
	 */
	function _onChange() {
		emits("update:modelValue", valueSync.value)
		emits("change", valueSync.value)
	}
</script>

<style lang="scss" scoped>
	.xl-rate {
		/* #ifndef APP-NVUE */
		display: flex;
		/* #endif */
		line-height: 1;
		font-size: 0;
		flex-direction: row;
		/* #ifdef H5 */
		cursor: pointer;
		/* #endif */
	}

	.xl-rate__icon {
		position: relative;
		line-height: 1;
		font-size: 0;
	}

	.xl-rate__icon-on {
		overflow: hidden;
		position: absolute;
		top: 0;
		left: 0;
		line-height: 1;
		text-align: left;
	}

	.xl-cursor-not-allowed {
		/* #ifdef H5 */
		cursor: not-allowed !important;
		/* #endif */
	}
</style>
